/*******************************************************************************
 * Copyright (c) 2011 EclipseDevX.org and others.
 * 
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at:
 * 
 *     http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/

package org.eclipsedevx.core.graphing;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.progress.UIJob;
import org.eclipsedevx.core.DevXCorePlugin;

/**
 * 
 * @author dcarew
 */
public class GraphControl extends Composite {
	private Label label;
	private String baseUrl;
	
	private Map<String, Image> imageCache = new HashMap<String, Image>();
	
	public GraphControl(Composite parent, int flags) {
		super(parent, flags);
		
		setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
		GridLayoutFactory.fillDefaults().applyTo(this);
		
		label = new Label(this, SWT.NONE);
		label.setBackground(getBackground());
		label.addControlListener(new ControlAdapter() {
			public void controlResized(ControlEvent e) {
				handleResized();
			}
		});
		
		GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true)
			.hint(100, 100).applyTo(label);
	}
	
	public void setGraphUrl(String url) {
		// http://chart.apis.google.com/chart?chxr=0,0,2750&chxt=y&chs=350x180&cht=lc&chco=3072F3&chds=0,2500&chd=t:787.553,1115.255,1307.616,1535.038,1813.098,1678.481,1738.126,1562.506,1563.512,1757.503,1889.952,2227.111,2026.646,2056.46,2182.829,1916.671,1637.504,1502.306,1497.994,1421.31&chg=14.3,-1,1,1&chls=2,4,0
		baseUrl = url;
		
		clearCache();
		
		label.setImage(null);
		
		if (baseUrl != null) {
		    updateImage(true);
		}
	}

	@Override
	public void dispose() {
		clearCache();
		
		super.dispose();
	}
	
	private void clearCache() {
		if (!label.isDisposed()) {
			label.setImage(null);
		}
		
		for (Image image : imageCache.values()) {
			image.dispose();
		}
		
		imageCache.clear();
	}

	private void handleResized() {
		Image image = imageCache.get(getCacheKey(label.getSize()));
		
		if (image == null) {
			updateImage(false);
		} else {
			label.setImage(image);
			label.redraw();
		}
	}

	private void updateImage(boolean force) {
		if (force) {
			LoadImageJob job = new LoadImageJob(label.getSize());
			
			job.schedule();
		} else {
			DelayImageJob job = new DelayImageJob(label.getSize());
			
			job.schedule(250);
		}		
	}
	
	private String getCacheKey(Point size) {
		// &chs=200x100
		
		int width = Math.min(1000, size.x);
		int height = Math.min(1000, size.y);
		
		if (width * height > 300000) {
			height = 300000 / width;
		}
		
		return "&chs=" + width + "x" + height;
	}
	
	class DelayImageJob extends UIJob {
		private Point size;
		
		public DelayImageJob(Point size) {
			super("Resize graph");
			
			this.size = size;
			
			setSystem(true);
		}

		@Override
		public IStatus runInUIThread(IProgressMonitor monitor) {
			if (!label.isDisposed()) {
				if (size.equals(label.getSize())) {
					updateImage(true);
				}
				
				return Status.OK_STATUS;
			} else {
				return Status.OK_STATUS;
			}
		}		
	}
	
	class LoadImageJob extends Job {
		private Point size;
		
		private ImageData imageData;
		
		public LoadImageJob(Point size) {
			super("Load graph image");
			
			this.size = size;
			
			setSystem(true);
		}

		@Override
		protected IStatus run(IProgressMonitor monitor) {
			try {
				if (!isDisposed()) {
					URL url = new URL(baseUrl + getCacheKey(size));
					ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(url);
					
					imageData = imageDescriptor.getImageData();
					
					createImage();
				}
			} catch (MalformedURLException e) {
				DevXCorePlugin.logError(e);
			}
			
			return Status.OK_STATUS;
		}

		private void createImage() {
			Display.getDefault().asyncExec(new Runnable() {
				public void run() {
					Image image = ImageDescriptor.createFromImageData(imageData).createImage();
					
					imageCache.put(getCacheKey(size), image);
					
					if (!label.isDisposed()) {
						label.setImage(image);
					}
				}
			});
		}
		
	}
	
}
